#include "rfid.h"

#include <QDebug>

#if 1
extern "C"
{
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <termios.h>
#include <unistd.h>
#include <string.h>
}


Rfid::Rfid()
{

}

void Rfid::run()
{
   int fd;

   fd = open(DEV_PATH, O_RDWR | O_NOCTTY | O_NONBLOCK);
   if (fd < 0)
   {
       fprintf(stderr, "Open com fail!\n");
       return;
   }
   /*初始化串口*/
   init_tty(fd);
   timeout.tv_sec = 2;
   timeout.tv_usec = 0;
printf("start %s\n", DEV_PATH);
   if(mode(fd))
   {
       //printf("The mode failed!\n");
       sleep(2);
       close(fd);
   }
   close(fd);
   sleep(2);
   printf("init OK\n");

   while(1)
   {
       flag=0;
       fd = open(DEV_PATH, O_RDWR | O_NOCTTY | O_NONBLOCK);
       if (fd < 0)
       {
           fprintf(stderr, "Open com fail!\n");
           return;
       }
       /*初始化串口*/
       init_tty(fd);
       timeout.tv_sec = 1;
       timeout.tv_usec = 0;
       mode(fd);

       /*请求天线范围的卡*/
       if ( PiccRequest(fd) )
       {
           //printf("The request failed!\n");

           //emit sendCardId(1);
           msleep(10);
           close(fd);
           continue;
       }
       /*进行防碰撞，获取天线范围内最大的ID*/
       if( PiccAnticoll(fd) )
       {
           printf("Couldn't get card-id!\n");
           //emit sendCardId(1);
           msleep(10);
           close(fd);
           continue;
       }
       if(out(fd))
       {
           printf("The out failed!\n");
           //emit sendCardId(1);
           msleep(10);
           close(fd);
           continue;
       }

        if(flag==1)
        {
           //printf("card ID = %u\n", cardid);
           //信号发送cardid
           //emit sendCardId(cardid);
            QDateTime currentDateTime = QDateTime::currentDateTime();
            QString time = currentDateTime.toString("yyyy-MM-dd_hh_mm_ss");
            emit sigCard(QString::number(cardid), time);

        }
        else
        {
            //printf("card ID = %u\n", 0);
            //emit sendCardId(0);
        }

       close(fd);
       msleep(10);
   }
   qDebug() << "*****end";
}

/* 设置窗口参数:9600速率 */
void Rfid::init_tty(int fd)
{
    //声明设置串口的结构体
    struct termios termios_new;
    //先清空该结构体
    bzero( &termios_new, sizeof(termios_new));
    //	cfmakeraw()设置终端属性，就是设置termios结构中的各个参数。
    cfmakeraw(&termios_new);
    //设置波特率
    //termios_new.c_cflag=(B9600);
    cfsetispeed(&termios_new, B115200);
    cfsetospeed(&termios_new, B115200);
    //CLOCAL和CREAD分别用于本地连接和接受使能，因此，首先要通过位掩码的方式激活这两个选项。
    termios_new.c_cflag |= CLOCAL | CREAD;
    //通过掩码设置数据位为8位
    termios_new.c_cflag &= ~CSIZE;
    termios_new.c_cflag |= CS8;
    //设置无奇偶校验
    termios_new.c_cflag &= ~PARENB;
    //一位停止位
    termios_new.c_cflag &= ~CSTOPB;
    tcflush(fd,TCIFLUSH);
    // 可设置接收字符和等待时间，无特殊要求可以将其设置为0
    termios_new.c_cc[VTIME] = 20;
    termios_new.c_cc[VMIN] = 1;
    // 用于清空输入/输出缓冲区
    tcflush (fd, TCIFLUSH);
    //完成配置后，可以使用以下函数激活串口设置
    if(tcsetattr(fd,TCSANOW,&termios_new) )
        printf("Setting the serial1 failed!\n");

}

int Rfid::mode(int fd)
{
    unsigned char WBuf[128], RBuf[128];
    int  ret;
    fd_set rdfd;

    memset(WBuf, 0, 128);
    memset(RBuf,1,128);
    WBuf[0] = 0x7f;
    WBuf[1] = 0x0C;
    WBuf[2] = 0xf7;

    FD_ZERO(&rdfd);
    FD_SET(fd,&rdfd);

    write(fd, WBuf, 3);
    msleep(10);
    ret = select(fd + 1,&rdfd, NULL,NULL,&timeout);
    switch(ret)
    {
        case -1:
            break;
        case  0:
            break;
        default:
            ret = read(fd, RBuf, 3);
            if (ret < 0)
            {
                printf("ret = %d, %m\n", ret, errno);
                break;
            }
            /*int i;
            for(i=0;i<ret;i++)
            {
                printf("rx = %d, %x\n", i, RBuf[i]);
            }*/
            if (RBuf[0] == 0x7f && RBuf[1] == 0xf7)	 	//应答帧状态部分为0 则请求成功
            {
                //return 0;
            }
            break;
    }

    memset(WBuf, 0, 128);
    memset(RBuf,1,128);
    WBuf[0] = 0x01;

    FD_ZERO(&rdfd);
    FD_SET(fd,&rdfd);

    write(fd, WBuf, 1);
    msleep(10);
    ret = select(fd + 1,&rdfd, NULL,NULL,&timeout);
    switch(ret)
    {
        case -1:
            perror("select error\n");
            break;
        case  0:
            //printf("mode error\n");
            break;
        default:
            ret = read(fd, RBuf, 1);
            if (ret < 0)
            {
                printf("ret = %d, %m\n", ret, errno);
                break;
            }
            /*int i;
            for(i=0;i<ret;i++)
            {
                printf("rx = %d, %x\n", i, RBuf[i]);
            }*/
            if (RBuf[0] == 0x01)	 	//应答帧状态部分为0 则请求成功
            {
                return 0;
            }
            break;
    }
    return -1;
}

int Rfid::out(int fd)
{
    unsigned char WBuf[128], RBuf[128];
    int  ret;
    fd_set rdfd;

    memset(WBuf, 0, 128);
    memset(RBuf,1,128);
    WBuf[0] = 0x7f;
    WBuf[1] = 0x0B;
    WBuf[2] = 0xf7;

    FD_ZERO(&rdfd);
    FD_SET(fd,&rdfd);

    write(fd, WBuf, 3);
    msleep(30);
    ret = select(fd + 1,&rdfd, NULL,NULL,&timeout);
    switch(ret)
    {
        case -1:
            perror("select error\n");
            break;
        case  0:
            printf("out error\n");
            break;
        default:
            ret = read(fd, RBuf, 2);
            if (ret < 0)
            {
                printf("ret = %d, %m\n", ret, errno);
                break;
            }
            /*int i;
            for(i=0;i<ret;i++)
            {
                printf("rx = %d, %x\n", i, RBuf[i]);
            }*/
            if (RBuf[0] == 0x7f && RBuf[1] == 0xf7)	 	//应答帧状态部分为0 则请求成功
            {
                return 0;
            }
            break;
    }
    return -1;
}

/*计算校验和*/
unsigned char Rfid::CalBCC(unsigned char *buf, int n)
{
    int i;
    unsigned char bcc=0;
    for(i = 0; i < n; i++)
    {
        bcc ^= *(buf+i);
    }
    return (~bcc);
}

int Rfid::PiccRequest(int fd)
{
    unsigned char WBuf[128], RBuf[128];
    int  ret;
    fd_set rdfd;

    memset(WBuf, 0, 128);
    memset(RBuf,1,128);
    WBuf[0] = 0x7F;
    WBuf[1] = 0x03;
    WBuf[2] = 0x52;
    WBuf[3] = 0xF7;

    FD_ZERO(&rdfd);
    FD_SET(fd,&rdfd);

    write(fd, WBuf, 4);
    msleep(40);
    ret = select(fd + 1,&rdfd, NULL,NULL,&timeout);
    switch(ret)
    {
        case -1:
            perror("select error\n");
            break;
        case  0:
            //printf("Request timed out.\n");
            break;
        default:
            ret = read(fd, RBuf, 10);
            if (ret < 0)
            {
                printf("ret = %d, %m\n", ret, errno);
                break;
            }
            /*int i;
            for(i=0;i<ret;i++)
            {
                printf("rx = %d, %x\n", i, RBuf[i]);
            }*/
            if (RBuf[0] == 0x7F )	 	//应答帧状态部分为0 则请求成功
            {
                //printf("Request OK\n");
                if(RBuf[3] == 0xF7)
                {
                    flag=1;
                }else
                {
                    flag=0;
                }
                return 0;
            }
            else{
                return 1;
            }
            break;
    }
    return -1;
}

/*防碰撞，获取范围内最大ID*/
int Rfid::PiccAnticoll(int fd)
{
    unsigned char WBuf[128], RBuf[128];
    int ret;
    fd_set rdfd;;
    memset(WBuf, 0, 128);
    memset(RBuf,0,128);
    WBuf[0] = 0x7f;	//帧长= 8 Byte
    WBuf[1] = 0x04;	//包号= 0 , 命令类型= 0x01
    WBuf[2] = 0xf7;	//命令= 'B'

    FD_ZERO(&rdfd);
    FD_SET(fd,&rdfd);
    write(fd, WBuf, 3);
    msleep(30);
    ret = select(fd + 1,&rdfd, NULL,NULL,&timeout);
    switch(ret)
    {
        case -1:
            perror("select error\n");
            break;
        case  0:
            perror("Timeout:");
            break;
        default:
            ret = read(fd, RBuf, 6);
            if (ret < 0)
            {
                printf("ret = %d, %m\n", ret, errno);
                break;
            }
            /*int i;
            for(i=0;i<ret;i++)
            {
                printf("rx = %d, %x\n", i, RBuf[i]);
            }*/
            if (RBuf[0] == 0x7f) //应答帧状态部分为0 则获取ID 成功
            {
                if(RBuf[5]==0xF7)
                {
                    flag=1;
                    cardid = (RBuf[4]<<24) | (RBuf[3]<<16) | (RBuf[2]<<8) | RBuf[1];
                }
                else
                {
                    flag=0;
                }
                return 0;
            }
    }
    return -1;
}
#endif
